#include "searchSortHandler.h"

sortHandler::sortHandler(){
}


// Below are structures that aid the algorithm sort function
// By comparing the different attribute properties and returning a boolean value
//@author A0097379H
struct nameSort
{
	bool nameSort::operator ()(FloatingTask* task1, FloatingTask* task2) {
		string string1 = task1->getTitle();
		string string2 = task2->getTitle();
		int compare = string1.compare(string2);
		if (compare < 0)
			return true;
		else 
			return false;
	}
};
nameSort nS;

struct locationSort
{
	bool locationSort::operator ()(FloatingTask* task1, FloatingTask* task2) {
		string string1 = task1->getLocation();
		string string2 = task2->getLocation();
		int compare = string1.compare(string2);
		if (compare < 0)
			return true;
		else 
			return false;
	}
};
locationSort lS;

struct personSort
{
	bool personSort::operator ()(FloatingTask* task1, FloatingTask* task2) {
		string string1 = task1->getPerson();
		string string2 = task2->getPerson();
		int compare = string1.compare(string2);
		if (compare < 0)
			return true;
		else 
			return false;
	}
};
personSort peS;

struct descriptionSort
{
	bool descriptionSort::operator ()(FloatingTask* task1, FloatingTask* task2) {
		string string1 = task1->getDescription();
		string string2 = task2->getDescription();
		int compare = string1.compare(string2);
		if (compare < 0)
			return true;
		else 
			return false;
	}
};
descriptionSort dS;

struct startTimeSort
{
	bool startTimeSort::operator ()(FloatingTask* task1, FloatingTask* task2) {
		time_t time1 = task1->getStartTimeAndDate();
		time_t time2 = task2->getStartTimeAndDate();
		if (time1 < time2)
			return true;
		else 
			return false;
	}
};
startTimeSort stS;

struct endTimeSort
{
	bool endTimeSort::operator ()(FloatingTask* task1, FloatingTask* task2) {
		time_t time1 = task1->getEndTimeAndDate();
		time_t time2 = task2->getEndTimeAndDate();
		if (time1 < time2)
			return true;
		else 
			return false;
	}
};
startTimeSort etS;

struct prioritySort
{
	bool prioritySort::operator ()(FloatingTask* task1, FloatingTask* task2) {
		int int1 = task1->getPriority();
		int int2 = task2->getPriority();
		int compare = int1 < int2;
		if (compare > 0)
			return true;
		else 
			return false;
	}
};
prioritySort pS;

struct finishedSort
{
	bool finishedSort::operator ()(FloatingTask* task1, FloatingTask* task2) {
		int int1 = task1->getPriority();
		int int2 = task2->getPriority();
		int compare = int1 < int2;
		if (compare > 0)
			return true;
		else 
			return false;
	}
};
finishedSort fS;

string sortHandler::sortName(vector<FloatingTask*> storageVector){
	string trackResults;
	sort(storageVector.begin(), storageVector.end(), nS);
	for (unsigned int i = 0; i < storageVector.size(); i++){
		if ((storageVector[i]->getTitle()).empty()){
			storageVector.erase(storageVector.begin() + i);
			i--;
		}
	}
	for (unsigned int i = 0; i < storageVector.size(); i++){
		trackResults += to_string(i+1) + CommonConstant::END_LINE + storageVector[i]->taskInfomation() + CommonConstant::END_LINE;
	}
	return trackResults;
}

string sortHandler::sortLocation(vector<FloatingTask*> storageVector){
	string trackResults;
	sort(storageVector.begin(), storageVector.end(), lS);
	for (unsigned int i = 0; i <storageVector.size(); i++){
		if ((storageVector[i]->getLocation()).empty()){
			storageVector.erase(storageVector.begin() + i);
			i--;
		}
	}
	for (unsigned int i = 0; i < storageVector.size(); i++){
		trackResults += to_string(i+1) + CommonConstant::END_LINE + storageVector[i]->taskInfomation() + CommonConstant::END_LINE;
	}
	return trackResults;
}

string sortHandler::sortPerson(vector<FloatingTask*> storageVector){
	string trackResults; 
	sort(storageVector.begin(), storageVector.end(), peS);
	for (unsigned int i = 0; i < storageVector.size(); i++){
		if ((storageVector[i]->getPerson()).empty()){
			storageVector.erase(storageVector.begin() + i);
			i--;
		}
	}
	for (unsigned int i = 0; i < storageVector.size(); i++){
		trackResults += to_string(i+1) + CommonConstant::END_LINE + storageVector[i]->taskInfomation() + CommonConstant::END_LINE;
	}
	return trackResults;
}

string sortHandler::sortDescription(vector<FloatingTask*> storageVector){
	string trackResults; 
	sort(storageVector.begin(), storageVector.end(), dS);
	for (unsigned int i = 0; i < storageVector.size(); i++){
		if ((storageVector[i]->getDescription()).empty()){
			storageVector.erase(storageVector.begin() + i);
			i--;
		}
	}
	for (unsigned int i = 0; i < storageVector.size(); i++){
		trackResults += to_string(i+1) + CommonConstant::END_LINE + storageVector[i]->taskInfomation() + CommonConstant::END_LINE;
	}
	return trackResults;
}

string sortHandler::sortStartDate(vector<FloatingTask*> storageVector){
	string trackResults;
	time_t currenttime;
	time(&currenttime);
	sort(storageVector.begin(), storageVector.end(), stS);
	for (unsigned int i = 0; i < storageVector.size(); i++){
		if (storageVector[i]->getTaskType() == CommonConstant::TASK_TYPE_FLOATING){
			storageVector.erase(storageVector.begin() + i);
			i--;
		}
	}
	for (unsigned int i = 0; i < storageVector.size(); i++){
		trackResults += to_string(i+1) + CommonConstant::END_LINE + storageVector[i]->taskInfomation() + CommonConstant::END_LINE;
	}
	return trackResults;
}

string sortHandler::sortEndDate(vector<FloatingTask*> storageVector){
	string trackResults;
	time_t currenttime;
	time(&currenttime);
	sort(storageVector.begin(), storageVector.end(), etS);
	for (unsigned int i = 0; i < storageVector.size(); i++){
		if (storageVector[i]->getTaskType() == CommonConstant::TASK_TYPE_FLOATING){
			storageVector.erase(storageVector.begin() + i);
			i--;
		}
	}
	for (unsigned int i = 0; i < storageVector.size(); i++){
		trackResults += to_string(i+1) + CommonConstant::END_LINE + storageVector[i]->taskInfomation() + CommonConstant::END_LINE;
	}
	return trackResults;
}

//displays all upcoming timed task in order for the main menu of the GUI
string sortHandler::sortStartDefault(vector<FloatingTask*> storageVector){
	string trackResults;
	time_t currenttime;
	currenttime = time(&currenttime);
	sort(storageVector.begin(), storageVector.end(), stS);
	for (unsigned int i = 0; i < storageVector.size(); i++){
		if (storageVector[i]->getTaskType() == CommonConstant::TASK_TYPE_FLOATING || storageVector[i]->getTaskType() == CommonConstant::TASK_TYPE_DEADLINE || storageVector[i]->getStringFinishedStatus() == CommonConstant::TASK_STRING_STATUS_FINISHED || (storageVector[i]->getStartTimeAndDate() < currenttime)){
			storageVector.erase(storageVector.begin() + i);
			i--;
		}
	}
	for (unsigned int i = 0; i < storageVector.size(); i++){
		trackResults += to_string(i+1) + CommonConstant::END_LINE + storageVector[i]->basicTaskInfomation() + CommonConstant::END_LINE;
	}
	return trackResults;
}

string sortHandler::sortPriority(vector<FloatingTask*> storageVector){
	string trackResults;
	sort(storageVector.begin(), storageVector.end(), pS);
	for (unsigned int i = 0; i < storageVector.size(); i++){
		trackResults += to_string(i+1) + CommonConstant::END_LINE + storageVector[i]->taskInfomation() + CommonConstant::END_LINE;
	}
	return trackResults;
}

string sortHandler::sortFinished(vector<FloatingTask*> storageVector){
	string trackResults; 
	sort(storageVector.begin(), storageVector.end(), fS);
	for (unsigned int i = 0; i < storageVector.size(); i++){
		trackResults += to_string(i+1) + CommonConstant::END_LINE + storageVector[i]->taskInfomation() + CommonConstant::END_LINE;
	}
	return trackResults;
}

string sortHandler::sortAll(vector<FloatingTask*> storageVector){
	string trackResults;
	for (unsigned int i = 0; i < storageVector.size(); i++){
		trackResults += to_string(i+1) + CommonConstant::END_LINE + storageVector[i]->taskInfomation() + CommonConstant::END_LINE;
	}
	return trackResults;
}

string sortHandler::sortIndex(vector<FloatingTask*> storageVector, string indexString){
	string trackResults;
	bool isIndex = true;
	for (unsigned int i = 0; i < indexString.length(); i++){
		if(isdigit(indexString[i])){
			isIndex = isIndex;
		}
		else {
			isIndex = false;
		}
	}
	if (isIndex){
		unsigned int index = atoi(indexString.c_str());
		if (index > storageVector.size()-1){
			return CommonConstant::MESSAGE_INDEX_OUT_OF_RANGE;
		}
		trackResults += storageVector[index]->taskInfomation() + CommonConstant::END_LINE;
	}
	else {
		trackResults = MESSAGE_INVALID_COMMAND;
	}
	return trackResults;
}

sortHandler::COMMAND_TYPE sortHandler::determineCommandType(string command){
	if(command == CommonConstant::KEYWORD_TASK_TITLE)
		return sortHandler::SORT_TASK;
	else if(command == CommonConstant::KEYWORD_TASK_LOCATION)
		return sortHandler::SORT_LOCATION;
	else if(command == CommonConstant::KEYWORD_TASK_PERSON)
		return sortHandler::SORT_PERSON;
	else if(command == CommonConstant::KEYWORD_TASK_DESCRIPTION)
		return sortHandler::SORT_DESCRIPTION;
	else if(command == CommonConstant::KEYWORD_SEARCH_TIME)
		return sortHandler::SORT_START_TIME;
	else if(command == CommonConstant::KEYWORD_END_TIME)
		return sortHandler::SORT_END_TIME;
	else if(command == CommonConstant::KEYWORD_SEARCH_DEFAULT)
		return sortHandler::SORT_START_DEFAULT;
	else if(command == CommonConstant::KEYWORD_TASK_PRIORITY)
		return sortHandler::SORT_PRIORITY;
	else if(command == CommonConstant::KEYWORD_TASK_FINISHED_STATUS)
		return sortHandler::SORT_FINISHED;
	else if(command.empty())
		return sortHandler::SORT_ALL;
	else if(isdigit(command[0]))
		return sortHandler::SORT_INDEX;
	else
		return sortHandler::INVALID;
}

string sortHandler::executeCommand(string userCommand, vector<FloatingTask*> taskList){
	string commandTypeString = userCommand;
	COMMAND_TYPE commandType = determineCommandType(commandTypeString);
	switch (commandType)
	{
	case sortHandler::SORT_TASK:
		return sortName(taskList);
	case sortHandler::SORT_LOCATION:
		return sortLocation(taskList);
	case sortHandler::SORT_PERSON:
		return sortPerson(taskList);
	case sortHandler::SORT_DESCRIPTION:
		return sortDescription(taskList);
	case sortHandler::SORT_START_TIME:
		return sortStartDate(taskList);
	case sortHandler::SORT_END_TIME:
		return sortEndDate(taskList);
	case sortHandler::SORT_START_DEFAULT:
		return sortStartDefault(taskList);
	case sortHandler::SORT_PRIORITY:
		return sortPriority(taskList);
	case sortHandler::SORT_FINISHED:
		return sortFinished(taskList);
	case sortHandler::SORT_ALL:
		return sortAll(taskList);
	case sortHandler::SORT_INDEX:
		return sortIndex(taskList, userCommand);
	case sortHandler::INVALID:
		return MESSAGE_INVALID_COMMAND;
	default:
		throw new exception("unrecongnized command type");
	}
}

const string sortHandler::MESSAGE_INVALID_COMMAND = "Error, command issued is invalid";
const string sortHandler::MESSAGE_SEARCH_NO_RESULT = "Error, no results found";